{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "bb0cc4aa-9f03-487c-807e-84bd6fe32028",
   "metadata": {},
   "source": [
    "# LangGraph 101: Conditional Routing\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Imports and State Definition\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import TypedDict\n",
    "from langgraph.graph import StateGraph, START, END\n",
    "from IPython.display import Image, display\n",
    "from rich import print"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63cfdb1d-d25f-4d28-b583-69b62c348d69",
   "metadata": {},
   "source": [
    "## State Definition\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e7fee5a9-ad6f-4c0d-895f-e657543a3e27",
   "metadata": {},
   "outputs": [],
   "source": [
    "class NumberState(TypedDict):\n",
    "    number: int\n",
    "    result: int"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3cc3346-44a7-4593-a98d-fe30baef546d",
   "metadata": {},
   "source": [
    "## Node Functions and Router\n",
    "\n",
    "We've set up three processing nodes to handle different types of numbers:\n",
    "\n",
    "- **Positive numbers**: We square the number.\n",
    "- **Negative numbers**: We take the absolute value.\n",
    "- **Zero**: We leave it as zero.\n",
    "\n",
    "Additionally, we've built a router function that decides which path to follow based on the sign of the input number.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "d9b863b0-3ffc-4921-97c7-a7afe73f852a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def abs_node(state: NumberState) -> NumberState:\n",
    "    \"\"\"If negative: take absolute value\"\"\"\n",
    "    state[\"result\"] = abs(state[\"number\"])\n",
    "    return state\n",
    "\n",
    "\n",
    "def square_node(state: NumberState) -> NumberState:\n",
    "    \"\"\"If positive: square the number\"\"\"\n",
    "    state[\"result\"] = state[\"number\"] ** 2\n",
    "    return state\n",
    "\n",
    "\n",
    "def zero_node(state: NumberState) -> NumberState:\n",
    "    \"\"\"If zero: leave as zero\"\"\"\n",
    "    state[\"result\"] = 0\n",
    "    return state\n",
    "\n",
    "\n",
    "def route_by_sign(state: NumberState) -> str:\n",
    "    \"\"\"Choose next node based on the sign of the number\"\"\"\n",
    "    if state[\"number\"] > 0:\n",
    "        return \"positive_branch\"\n",
    "    elif state[\"number\"] < 0:\n",
    "        return \"negative_branch\"\n",
    "    else:\n",
    "        return \"zero_branch\"\n",
    "\n",
    "\n",
    "# Build the graph\n",
    "graph = StateGraph(NumberState)\n",
    "\n",
    "# Add our transformation nodes\n",
    "graph.add_node(\"square_node\", square_node)\n",
    "graph.add_node(\"abs_node\", abs_node)\n",
    "graph.add_node(\"zero_node\", zero_node)\n",
    "\n",
    "# A passthrough router node\n",
    "# graph.add_node(\"router\", lambda s: s)\n",
    "\n",
    "\n",
    "def passthrough_router(state):\n",
    "    return state\n",
    "\n",
    "\n",
    "graph.add_node(\"router\", passthrough_router)\n",
    "\n",
    "# Link start → router\n",
    "graph.add_edge(START, \"router\")\n",
    "\n",
    "# Conditional edges from router into each branch\n",
    "graph.add_conditional_edges(\n",
    "    \"router\",\n",
    "    route_by_sign,\n",
    "    {\"positive_branch\": \"square_node\", \"negative_branch\": \"abs_node\", \"zero_branch\": \"zero_node\"},\n",
    ")\n",
    "\n",
    "# All branches lead to END\n",
    "graph.add_edge(\"square_node\", END)\n",
    "graph.add_edge(\"abs_node\", END)\n",
    "graph.add_edge(\"zero_node\", END)\n",
    "\n",
    "# Compile into an executable app\n",
    "app = graph.compile()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "63c0706d-0bfc-4793-adaa-a937fcbe4b52",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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aNAXX3yBPXvt2rVLly5lZmY6OTl17dp14MCB2MpSq9W//fbbw4cPGQxGt27dvL29ly1bdvToUTMzM7FYfOrUqcTExKysLDMzs44dO44fP57FYs2fP//FixcIoRs3buzYsSM5OXn37t2XLl2aO3cui8X6+eef8ZKWLVtWUVGxdetWpVJ58ODBuLi4goICb2/v/v37h4SE1PhbaDQaiUSCH6Gw2ez9+/ffu3dPo9F069YtMjKSSqW+e/du2rRpK1eu3Lp1q4mJSVRUVGZm5sWLF589e/bx48fWrVtHRET07dsXW8KIESPGjRtXUVFx5MgRFosVGBg4depUbDiOUCj8448/rl69amxsHBAQ8NVXX1Wd4fjXX3+9fPmymZlZ586dv/3228ZuPqKcOnUqJiZm9uzZ27dvLysrs7GxGT16dHh4OPbso0ePjhw5kp2djd3tZvr06divJhKJsClvSktL3d3de/ToERERgfUGiESitWvXYj9u2bJl9+7dp06dwh5ftmzZ8OHDx44dO3LkSGz5KpVq6NCh/fr1++qrr0pKSnbv3p2amlpZWRkYGDh69Gh7e3vsZZWVlbUlLIVCycvLO3jwYHx8vIWFxbBhw7DiY2Njjx8/PnPmzNWrV/fr12/atGmPHz++c+dOcnKyUChs27bt6NGj/fz8EEKZmZlTp0799ddfjx8//vDhQwsLi65du3711VfYgU52dvavv/6anJxsY2Pz+eefjx8/Hj/0KSkpWbt2bWpqqp2d3bBhw7BfWd/NmDHjzZs3VR/p3r37woULEUKpqanR0dEvX740Njbu0KHD2LFjORxOjataIpFs3749KSlJJBK1bt26V69e2D2TmEymRCLBxt4pFIpqZz70fVM2tB+WTqeLRKKoqKg5c+Zcvny5S5cuW7ZsKSgoQAjdvn178+bNrq6u+/fvnzhx4pkzZ3bu3Im96/Tp05cuXZo2bdr27dvZbPaBAwfw0U5nz56NiYkZMmTIihUrJk2adPfu3ejoaITQhg0bPDw8wsPDr1y54urqihcQGhr69OlTiUSC/SiTyZ48edK9e3eEUFRU1JkzZ/r373/w4MEuXbqsXr363r171erHzoqoVCoKhYIfqkRFRbm5uc2bN2/kyJEnT568evUq9psihI4ePTp06NDZs2djMxAmJiZOnz591apVERERv/32W1xcHLYEGo12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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "graph_img = Image(app.get_graph().draw_mermaid_png())\n",
    "display(graph_img)\n",
    "# save the graph to a file\n",
    "with open(\"../output/05-Conditional_Routing.png\", \"wb\") as f:\n",
    "    f.write(app.get_graph().draw_mermaid_png())\n",
    "# Mermaid is a popular diagramming syntax that can be rendered in many tools\n",
    "with open(\"../output/05-Conditional_Routing.mmd\", \"w\") as f:\n",
    "    f.write(app.get_graph().draw_mermaid())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d44c7226-d12b-4bd0-9d67-05b24581bc37",
   "metadata": {},
   "source": [
    "## Testing the Conditional Routing Graph\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "fda40dea-148d-4561-8db6-809d053e4b96",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Input:  <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">5</span> → Result: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">25</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "Input:  \u001b[1;36m5\u001b[0m → Result: \u001b[1;36m25\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Input: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">-3</span> → Result: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "Input: \u001b[1;36m-3\u001b[0m → Result: \u001b[1;36m3\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Input:  <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0</span> → Result: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "Input:  \u001b[1;36m0\u001b[0m → Result: \u001b[1;36m0\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Test it out:\n",
    "for test_number in [5, -3, 0]:\n",
    "    state: NumberState = {\"number\": test_number, \"result\": None}  # type: ignore\n",
    "    out = app.invoke(state)\n",
    "    print(f\"Input: {test_number:>2} → Result: {out['result']}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py312",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
